/**
 *
 */
package cn.edu.cqu.bysj.wm.ago.anlys;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.neo4j.graphdb.Node;
import org.ujmp.core.Matrix;
import org.ujmp.core.MatrixFactory;
import org.ujmp.core.calculation.Calculation.Ret;
import org.ujmp.core.enums.ValueType;

import cn.edu.cqu.bysj.wm.gui.result.DetectedResult;
import cn.edu.cqu.bysj.wm.util.CommunityOutput;

/**
 * @author Meng
 * 
 */
public class Similarity {

	public static long n;

	// map of solution id and community
	public static Map<Integer, Map<Long, List<Node>>> solutions = new HashMap<Integer, Map<Long, List<Node>>>();

	// map of solution id and Q value
	public static Map<Integer, Double> Qs = new HashMap<Integer, Double>();

	// jaccard index and fsame matrix
	public static Matrix M;

	public static int SID = 0;

	/**
	 * calc fsame and jaccard index fill the matrix M to compare each pair of
	 * solution
	 * 
	 */
	public static void calcFJ() {
		int sn = solutions.size();
		M = MatrixFactory.zeros(ValueType.FLOAT, sn, sn);

		// solution s1,s2, n1,n2 as community number in s1,s2
		for (int s1 = 1; s1 <= sn; s1++) {
			for (int s2 = s1 + 1; s2 <= sn; s2++) {
				int n1 = solutions.get(s1).size();
				int n2 = solutions.get(s2).size();
				float fsame = fsame(s1, s2, n1, n2);
				float jaccard = jaccard(s1, s2, n1, n2);
				M.setAsFloat(fsame, s1 - 1, s2 - 1);
				M.setAsFloat(jaccard, s2 - 1, s1 - 1);
			}
		}
		DetectedResult.setSolutionResult();
		CommunityOutput.outputSolutions();
	}

	/**
	 * calculate fsame in solution1 and 2
	 * 
	 * @param s1
	 *            solution1
	 * @param s2
	 *            solution2
	 * @param n1
	 *            community number in solution1
	 * @param n2
	 *            community number in solution2
	 * @return fsame value
	 */
	private static float fsame(int s1, int s2, int n1, int n2) {

		Matrix m = MatrixFactory.zeros(ValueType.INT, n1, n2);

		for (long i = 1; i <= n1; i++) {
			for (long j = 1; j <= n2; j++) {
				List<Node> li = new ArrayList<Node>(solutions.get(s1).get(i));
				List<Node> lj = new ArrayList<Node>(solutions.get(s2).get(j));
				li.retainAll(lj);
				int num = li.size();
				m.setAsInt(num, i - 1, j - 1);
				// m.setAsInt(num, j-1, i-1);
			}
		}

		float sumi = 0, sumj = 0;
		for (int i = 0; i < n1; i++) {
			sumi += m.selectRows(Ret.LINK, i).getMaxValue();
		}
		for (int j = 0; j < n2; j++) {
			sumj += m.selectColumns(Ret.LINK, j).getMaxValue();
		}

		float ans = (sumi + sumj) * 50 / n;
		return ans;
	}

	/**
	 * calculate jaccard index in solution1 and 2 n1 n2 are the number of
	 * community
	 * 
	 * @param s1
	 *            solution1
	 * @param s2
	 *            solution2
	 * @param n1
	 *            community number in solution1
	 * @param n2
	 *            community number in solution2
	 * @return jaccard index value
	 */
	private static float jaccard(int s1, int s2, int n1, int n2) {
		
		// the pair of node in s1
		Map<Long, Long> p1 = new HashMap<Long, Long>();
		// the pair of node in s2
		Map<Long, Long> p2 = new HashMap<Long, Long>();

		// caculate p1
		for (long i = 1; i <= n1; i++) {
			List<Node> l = solutions.get(s1).get(i);
			for (int k = 0; k < l.size(); k++) {
				for (int t = k + 1; t < l.size(); t++) {
					p1.put(l.get(k).getId(), l.get(t).getId());
				}
			}
		}
		// caculate p2
		for (long j = 1; j <= n2; j++) {
			List<Node> l = solutions.get(s2).get(j);
			for (int k = 0; k < l.size(); k++) {
				for (int t = k + 1; t < l.size(); t++) {
					p2.put(l.get(k).getId(), l.get(t).getId());
				}
			}
		}
		// a represents the number of pair of nodes in the same community in both s1
		// and s2
		float a = 0;
		for (long i : p1.keySet()) {
			for (long j : p2.keySet()) {
				if (i == j && p1.get(i) == p1.get(j)) {
					a++;
				}
			}
		}
		float ans = a / (p1.size() + p2.size() - a);
		return ans;
	}
}
